32. 消息

Spring Framework框架为集成消息系统提供了扩展(extensive)支持:从使用JmsTemplate简化JMS API,到实现一个能够异步接收消息的完整的底层设施。Spring AMQP提供一个相似的用于'高级消息队列协议'的特征集,并且Spring Boot也为RabbitTemplate和RabbitMQ提供了自动配置选项。Spring Websocket提供原生的STOMP消息支持,并且Spring Boot也提供了starters和自动配置支持。

32.1. JMS

javax.jms.ConnectionFactory接口提供标准的用于创建javax.jms.Connection的方法,javax.jms.Connection用于和JMS代理(broker)交互。 尽管Spring需要一个ConnectionFactory才能使用JMS,通常你不需要直接使用它,而是依赖于上层消息抽象(具体参考Spring框架的相关章节),Spring Boot会自动配置发送和接收消息需要的设施(infrastructure)。

32.1.1 ActiveQ支持

如果发现ActiveMQ在classpath下可用,Spring Boot会配置一个ConnectionFactory。如果需要代理,将会开启一个内嵌的,已经自动配置好的代理(只要配置中没有指定代理URL)。

ActiveMQ是通过spring.activemq.*外部配置来控制的,例如,你可能在application.properties中声明以下片段:

spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret

具体参考ActiveMQProperties

默认情况下,如果目标不存在,ActiveMQ将创建一个,所以目标是通过它们提供的名称解析出来的。

32.1.2 Artemis支持

Apache Artemis成立于2015年,那时HornetQ刚捐给Apache基金会,确保别使用了过期的HornetQ支持。 不要尝试同时使用Artemis和HornetQ。

如果发现classpath下存在Artemis依赖,Spring Boot将自动配置一个ConnectionFactory。如果需要broker,Spring Boot将启动内嵌的broker,并对其自动配置(除非模式mode属性被显式设置)。支持的modes包括:embedded(明确需要内嵌broker,如果classpath下不存在则出错),native(使用netty传输协议连接broker)。当配置native模式,Spring Boot将配置一个连接broker的ConnectionFactory,该broker使用默认的设置运行在本地机器。 使用spring-boot-starter-artemis 'Starter',则连接已存在的Artemis实例及Spring设施集成JMS所需依赖都会提供,添加org.apache.activemq:artemis-jms-server依赖,你可以使用内嵌模式。

Artemis配置控制在外部配置属性spring.artemis.*中,例如,在application.properties声明以下片段:

spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret

当使用内嵌模式时,你可以选择是否启用持久化,及目的地列表。这些可以通过逗号分割的列表来指定,也可以分别定义org.apache.activemq.artemis.jms.server.config.JMSQueueConfigurationorg.apache.activemq.artemis.jms.server.config.TopicConfiguration类型的bean来进一步配置队列和topic,具体支持选项可参考ArtemisProperties

32.1.3 HornetQ支持

HornetQ在1.4版本已过期,可以考虑迁移到artemis

如果在classpath下发现HornetQ,Spring Boot会自动配置ConnectionFactory。如果需要代理,将会开启一个内嵌的,已经自动配置好的代理(除非显式设置mode属性)。支持的modes有:embedded(显式声明使用内嵌的代理,如果该代理在classpath下不可用将出错),native(使用netty传输协议连接代理)。当后者被配置,Spring Boot配置一个连接到代理的ConnectionFactory,该代理运行在使用默认配置的本地机器上。

:如果使用spring-boot-starter-hornetq,连接到一个已存在的HornetQ实例所需的依赖都会被提供,同时还有用于集成JMS的Spring基础设施。将org.hornetq:hornetq-jms-server添加到应用中,你就可以使用embedded模式。

HornetQ配置被spring.hornetq.*中的外部配置属性所控制,例如,在application.properties声明以下片段:

spring.hornetq.mode=native
spring.hornetq.host=192.168.1.210
spring.hornetq.port=9876

当内嵌代理时,你可以选择是否启用持久化,并且列表中的目标都应该是可用的。这些可以通过一个以逗号分割的列表来指定一些默认的配置项,或定义org.hornetq.jms.server.config.JMSQueueConfigurationorg.hornetq.jms.server.config.TopicConfiguration类型的bean(s)来配置更高级的队列和主题,具体参考HornetQProperties

没有涉及JNDI查找,目标是通过名字解析的,名字即可以使用HornetQ配置中的name属性,也可以是配置中提供的names。

32.1.4 使用JNDI ConnectionFactory

如果你的App运行在应用服务器中,Spring Boot将尝试使用JNDI定位一个JMS ConnectionFactory,默认会检查java:/JmsXAjava:/ XAConnectionFactory两个地址。如果需要指定替换位置,可以使用spring.jms.jndi-name属性:

spring.jms.jndi-name=java:/MyConnectionFactory

32.1.5 发送消息

Spring的JmsTemplate会被自动配置,你可以将它直接注入到自己的beans中:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JmsTemplate jmsTemplate;
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
// ...
}

你可以使用相同方式注入JmsMessagingTemplate。如果定义了DestinationResolverMessageConverter beans,它们将自动关联到自动配置的JmsTemplate

32.1.6 接收消息

当JMS基础设施能够使用时,任何bean都能够被@JmsListener注解,以创建一个监听者端点。如果没有定义JmsListenerContainerFactory,将自动配置一个默认的。如果定义DestinationResolverMessageConverter beans,它们将自动关联该默认factory。

默认factory是事务性的,如果运行的设施出现JtaTransactionManager,它默认将关联到监听器容器。如果没有,sessionTransacted标记将启用。在后一场景中,你可以通过在监听器方法上添加@Transactional,以本地数据存储事务处理接收的消息,这可以确保接收的消息在本地事务完成后只确认一次。

下面的组件创建了一个以someQueue为目标的监听器端点:

@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}
}

具体查看@EnableJms javadoc

如果想创建多个JmsListenerContainerFactory实例或覆盖默认实例,你可以使用Spring Boot提供的DefaultJmsListenerContainerFactoryConfigurer,通过它可以使用跟自动配置的实例相同配置来初始化一个DefaultJmsListenerContainerFactory

例如,以下使用一个特殊的MessageConverter创建另一个factory:

@Configuration
static class JmsConfiguration {

    @Bean
    public DefaultJmsListenerContainerFactory myFactory(
            DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory =
                new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, connectionFactory());
        factory.setMessageConverter(myMessageConverter());
        return factory;
    }

}

然后,你可以像下面那样在任何@JmsListener注解中使用:

@Component
public class MyBean {

    @JmsListener(destination = "someQueue", containerFactory="myFactory")
    public void processMessage(String content) {
        // ...
    }

}

32.2 AMQP

高级消息队列协议(AMQP)是一个用于消息中间件的,平台无关的,线路级(wire-level)协议。Spring AMQP项目使用Spring的核心概念开发基于AMQP的消息解决方案,Spring Boot为通过RabbitMQ使用AMQP提供了一些便利,包括spring-boot-starter-amqp‘Starter’。

32.2.1 RabbitMQ支持

RabbitMQ是一个基于AMQP协议,轻量级的,可靠的,可扩展的和可移植的消息代理,Spring就使用它进行消息传递。RabbitMQ配置被外部属性spring.rabbitmq.*控制,例如,在application.properties中声明以下片段:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret

更多选项参考RabbitProperties

32.1.2 Artemis支持

Apache Artemis成立于2015年,那时HornetQ刚捐给Apache基金会,确保别使用了过期的HornetQ支持。 不要尝试同时使用Artemis和HornetQ。

如果发现classpath下存在Artemis依赖,Spring Boot将自动配置一个ConnectionFactory。如果需要broker,Spring Boot将启动内嵌的broker,并对其自动配置(除非模式mode属性被显式设置)。支持的modes包括:embedded(明确需要内嵌broker,如果classpath下不存在则出错),native(使用netty传输协议连接broker)。当配置native模式,Spring Boot将配置一个连接broker的ConnectionFactory,该broker使用默认的设置运行在本地机器。 使用spring-boot-starter-artemis 'Starter',则连接已存在的Artemis实例及Spring设施集成JMS所需依赖都会提供,添加org.apache.activemq:artemis-jms-server依赖,你可以使用内嵌模式。

Artemis配置控制在外部配置属性spring.artemis.*中,例如,在application.properties声明以下片段:

spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret

当使用内嵌模式时,你可以选择是否启用持久化,及目的地列表。这些可以通过逗号分割的列表来指定,也可以分别定义org.apache.activemq.artemis.jms.server.config.JMSQueueConfigurationorg.apache.activemq.artemis.jms.server.config.TopicConfiguration类型的bean来进一步配置队列和topic,具体支持选项可参考ArtemisProperties

32.1.3 HornetQ支持

HornetQ在1.4版本已过期,可以考虑迁移到artemis

如果在classpath下发现HornetQ,Spring Boot会自动配置ConnectionFactory。如果需要代理,将会开启一个内嵌的,已经自动配置好的代理(除非显式设置mode属性)。支持的modes有:embedded(显式声明使用内嵌的代理,如果该代理在classpath下不可用将出错),native(使用netty传输协议连接代理)。当后者被配置,Spring Boot配置一个连接到代理的ConnectionFactory,该代理运行在使用默认配置的本地机器上。

:如果使用spring-boot-starter-hornetq,连接到一个已存在的HornetQ实例所需的依赖都会被提供,同时还有用于集成JMS的Spring基础设施。将org.hornetq:hornetq-jms-server添加到应用中,你就可以使用embedded模式。

HornetQ配置被spring.hornetq.*中的外部配置属性所控制,例如,在application.properties声明以下片段:

spring.hornetq.mode=native
spring.hornetq.host=192.168.1.210
spring.hornetq.port=9876

当内嵌代理时,你可以选择是否启用持久化,并且列表中的目标都应该是可用的。这些可以通过一个以逗号分割的列表来指定一些默认的配置项,或定义org.hornetq.jms.server.config.JMSQueueConfigurationorg.hornetq.jms.server.config.TopicConfiguration类型的bean(s)来配置更高级的队列和主题,具体参考HornetQProperties

没有涉及JNDI查找,目标是通过名字解析的,名字即可以使用HornetQ配置中的name属性,也可以是配置中提供的names。

32.1.4 使用JNDI ConnectionFactory

如果你的App运行在应用服务器中,Spring Boot将尝试使用JNDI定位一个JMS ConnectionFactory,默认会检查java:/JmsXAjava:/ XAConnectionFactory两个地址。如果需要指定替换位置,可以使用spring.jms.jndi-name属性:

spring.jms.jndi-name=java:/MyConnectionFactory

32.1.5 发送消息

Spring的JmsTemplate会被自动配置,你可以将它直接注入到自己的beans中:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JmsTemplate jmsTemplate;
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
// ...
}

你可以使用相同方式注入JmsMessagingTemplate。如果定义了DestinationResolverMessageConverter beans,它们将自动关联到自动配置的JmsTemplate

32.1.6 接收消息

当JMS基础设施能够使用时,任何bean都能够被@JmsListener注解,以创建一个监听者端点。如果没有定义JmsListenerContainerFactory,将自动配置一个默认的。如果定义DestinationResolverMessageConverter beans,它们将自动关联该默认factory。

默认factory是事务性的,如果运行的设施出现JtaTransactionManager,它默认将关联到监听器容器。如果没有,sessionTransacted标记将启用。在后一场景中,你可以通过在监听器方法上添加@Transactional,以本地数据存储事务处理接收的消息,这可以确保接收的消息在本地事务完成后只确认一次。

下面的组件创建了一个以someQueue为目标的监听器端点:

@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}
}

具体查看@EnableJms javadoc

如果想创建多个JmsListenerContainerFactory实例或覆盖默认实例,你可以使用Spring Boot提供的DefaultJmsListenerContainerFactoryConfigurer,通过它可以使用跟自动配置的实例相同配置来初始化一个DefaultJmsListenerContainerFactory

例如,以下使用一个特殊的MessageConverter创建另一个factory:

@Configuration
static class JmsConfiguration {

    @Bean
    public DefaultJmsListenerContainerFactory myFactory(
            DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory =
                new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, connectionFactory());
        factory.setMessageConverter(myMessageConverter());
        return factory;
    }

}

然后,你可以像下面那样在任何@JmsListener注解中使用:

@Component
public class MyBean {

    @JmsListener(destination = "someQueue", containerFactory="myFactory")
    public void processMessage(String content) {
        // ...
    }

}

32.2 AMQP

高级消息队列协议(AMQP)是一个用于消息中间件的,平台无关的,线路级(wire-level)协议。Spring AMQP项目使用Spring的核心概念开发基于AMQP的消息解决方案,Spring Boot为通过RabbitMQ使用AMQP提供了一些便利,包括spring-boot-starter-amqp‘Starter’。

32.2.1 RabbitMQ支持

RabbitMQ是一个基于AMQP协议,轻量级的,可靠的,可扩展的和可移植的消息代理,Spring就使用它进行消息传递。RabbitMQ配置被外部属性spring.rabbitmq.*控制,例如,在application.properties中声明以下片段:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret

更多选项参考RabbitProperties

32.1.2 Artemis支持

Apache Artemis成立于2015年,那时HornetQ刚捐给Apache基金会,确保别使用了过期的HornetQ支持。 不要尝试同时使用Artemis和HornetQ。

如果发现classpath下存在Artemis依赖,Spring Boot将自动配置一个ConnectionFactory。如果需要broker,Spring Boot将启动内嵌的broker,并对其自动配置(除非模式mode属性被显式设置)。支持的modes包括:embedded(明确需要内嵌broker,如果classpath下不存在则出错),native(使用netty传输协议连接broker)。当配置native模式,Spring Boot将配置一个连接broker的ConnectionFactory,该broker使用默认的设置运行在本地机器。 使用spring-boot-starter-artemis 'Starter',则连接已存在的Artemis实例及Spring设施集成JMS所需依赖都会提供,添加org.apache.activemq:artemis-jms-server依赖,你可以使用内嵌模式。

Artemis配置控制在外部配置属性spring.artemis.*中,例如,在application.properties声明以下片段:

spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret

当使用内嵌模式时,你可以选择是否启用持久化,及目的地列表。这些可以通过逗号分割的列表来指定,也可以分别定义org.apache.activemq.artemis.jms.server.config.JMSQueueConfigurationorg.apache.activemq.artemis.jms.server.config.TopicConfiguration类型的bean来进一步配置队列和topic,具体支持选项可参考ArtemisProperties

32.1.3 HornetQ支持

HornetQ在1.4版本已过期,可以考虑迁移到artemis

如果在classpath下发现HornetQ,Spring Boot会自动配置ConnectionFactory。如果需要代理,将会开启一个内嵌的,已经自动配置好的代理(除非显式设置mode属性)。支持的modes有:embedded(显式声明使用内嵌的代理,如果该代理在classpath下不可用将出错),native(使用netty传输协议连接代理)。当后者被配置,Spring Boot配置一个连接到代理的ConnectionFactory,该代理运行在使用默认配置的本地机器上。

:如果使用spring-boot-starter-hornetq,连接到一个已存在的HornetQ实例所需的依赖都会被提供,同时还有用于集成JMS的Spring基础设施。将org.hornetq:hornetq-jms-server添加到应用中,你就可以使用embedded模式。

HornetQ配置被spring.hornetq.*中的外部配置属性所控制,例如,在application.properties声明以下片段:

spring.hornetq.mode=native
spring.hornetq.host=192.168.1.210
spring.hornetq.port=9876

当内嵌代理时,你可以选择是否启用持久化,并且列表中的目标都应该是可用的。这些可以通过一个以逗号分割的列表来指定一些默认的配置项,或定义org.hornetq.jms.server.config.JMSQueueConfigurationorg.hornetq.jms.server.config.TopicConfiguration类型的bean(s)来配置更高级的队列和主题,具体参考HornetQProperties

没有涉及JNDI查找,目标是通过名字解析的,名字即可以使用HornetQ配置中的name属性,也可以是配置中提供的names。

32.1.4 使用JNDI ConnectionFactory

如果你的App运行在应用服务器中,Spring Boot将尝试使用JNDI定位一个JMS ConnectionFactory,默认会检查java:/JmsXAjava:/ XAConnectionFactory两个地址。如果需要指定替换位置,可以使用spring.jms.jndi-name属性:

spring.jms.jndi-name=java:/MyConnectionFactory

32.1.5 发送消息

Spring的JmsTemplate会被自动配置,你可以将它直接注入到自己的beans中:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JmsTemplate jmsTemplate;
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
// ...
}

你可以使用相同方式注入JmsMessagingTemplate。如果定义了DestinationResolverMessageConverter beans,它们将自动关联到自动配置的JmsTemplate

32.1.6 接收消息

当JMS基础设施能够使用时,任何bean都能够被@JmsListener注解,以创建一个监听者端点。如果没有定义JmsListenerContainerFactory,将自动配置一个默认的。如果定义DestinationResolverMessageConverter beans,它们将自动关联该默认factory。

默认factory是事务性的,如果运行的设施出现JtaTransactionManager,它默认将关联到监听器容器。如果没有,sessionTransacted标记将启用。在后一场景中,你可以通过在监听器方法上添加@Transactional,以本地数据存储事务处理接收的消息,这可以确保接收的消息在本地事务完成后只确认一次。

下面的组件创建了一个以someQueue为目标的监听器端点:

@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}
}

具体查看@EnableJms javadoc

如果想创建多个JmsListenerContainerFactory实例或覆盖默认实例,你可以使用Spring Boot提供的DefaultJmsListenerContainerFactoryConfigurer,通过它可以使用跟自动配置的实例相同配置来初始化一个DefaultJmsListenerContainerFactory

例如,以下使用一个特殊的MessageConverter创建另一个factory:

@Configuration
static class JmsConfiguration {

    @Bean
    public DefaultJmsListenerContainerFactory myFactory(
            DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory =
                new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, connectionFactory());
        factory.setMessageConverter(myMessageConverter());
        return factory;
    }

}

然后,你可以像下面那样在任何@JmsListener注解中使用:

@Component
public class MyBean {

    @JmsListener(destination = "someQueue", containerFactory="myFactory")
    public void processMessage(String content) {
        // ...
    }

}

32.2 AMQP

高级消息队列协议(AMQP)是一个用于消息中间件的,平台无关的,线路级(wire-level)协议。Spring AMQP项目使用Spring的核心概念开发基于AMQP的消息解决方案,Spring Boot为通过RabbitMQ使用AMQP提供了一些便利,包括spring-boot-starter-amqp‘Starter’。

32.2.1 RabbitMQ支持

RabbitMQ是一个基于AMQP协议,轻量级的,可靠的,可扩展的和可移植的消息代理,Spring就使用它进行消息传递。RabbitMQ配置被外部属性spring.rabbitmq.*控制,例如,在application.properties中声明以下片段:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret

更多选项参考RabbitProperties

32.2.2 发送消息

Spring的AmqpTemplateAmqpAdmin会被自动配置,你可以将它们直接注入beans中:

import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final AmqpAdmin amqpAdmin;
    private final AmqpTemplate amqpTemplate;

    @Autowired
    public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
        this.amqpAdmin = amqpAdmin;
        this.amqpTemplate = amqpTemplate;
    }

    // ...

}

可以使用相似方式注入RabbitMessagingTemplate,如果定义MessageConverter bean,它将自动关联到自动配置的AmqpTemplate

如果需要的话,所有定义为bean的org.springframework.amqp.core.Queue将自动在RabbitMQ实例中声明相应的队列。你可以启用AmqpTemplate的重试选项,例如代理连接丢失时,重试默认不启用。

32.1.3 HornetQ支持

HornetQ在1.4版本已过期,可以考虑迁移到artemis

如果在classpath下发现HornetQ,Spring Boot会自动配置ConnectionFactory。如果需要代理,将会开启一个内嵌的,已经自动配置好的代理(除非显式设置mode属性)。支持的modes有:embedded(显式声明使用内嵌的代理,如果该代理在classpath下不可用将出错),native(使用netty传输协议连接代理)。当后者被配置,Spring Boot配置一个连接到代理的ConnectionFactory,该代理运行在使用默认配置的本地机器上。

:如果使用spring-boot-starter-hornetq,连接到一个已存在的HornetQ实例所需的依赖都会被提供,同时还有用于集成JMS的Spring基础设施。将org.hornetq:hornetq-jms-server添加到应用中,你就可以使用embedded模式。

HornetQ配置被spring.hornetq.*中的外部配置属性所控制,例如,在application.properties声明以下片段:

spring.hornetq.mode=native
spring.hornetq.host=192.168.1.210
spring.hornetq.port=9876

当内嵌代理时,你可以选择是否启用持久化,并且列表中的目标都应该是可用的。这些可以通过一个以逗号分割的列表来指定一些默认的配置项,或定义org.hornetq.jms.server.config.JMSQueueConfigurationorg.hornetq.jms.server.config.TopicConfiguration类型的bean(s)来配置更高级的队列和主题,具体参考HornetQProperties

没有涉及JNDI查找,目标是通过名字解析的,名字即可以使用HornetQ配置中的name属性,也可以是配置中提供的names。

32.1.4 使用JNDI ConnectionFactory

如果你的App运行在应用服务器中,Spring Boot将尝试使用JNDI定位一个JMS ConnectionFactory,默认会检查java:/JmsXAjava:/ XAConnectionFactory两个地址。如果需要指定替换位置,可以使用spring.jms.jndi-name属性:

spring.jms.jndi-name=java:/MyConnectionFactory

32.1.5 发送消息

Spring的JmsTemplate会被自动配置,你可以将它直接注入到自己的beans中:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JmsTemplate jmsTemplate;
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
// ...
}

你可以使用相同方式注入JmsMessagingTemplate。如果定义了DestinationResolverMessageConverter beans,它们将自动关联到自动配置的JmsTemplate

32.1.6 接收消息

当JMS基础设施能够使用时,任何bean都能够被@JmsListener注解,以创建一个监听者端点。如果没有定义JmsListenerContainerFactory,将自动配置一个默认的。如果定义DestinationResolverMessageConverter beans,它们将自动关联该默认factory。

默认factory是事务性的,如果运行的设施出现JtaTransactionManager,它默认将关联到监听器容器。如果没有,sessionTransacted标记将启用。在后一场景中,你可以通过在监听器方法上添加@Transactional,以本地数据存储事务处理接收的消息,这可以确保接收的消息在本地事务完成后只确认一次。

下面的组件创建了一个以someQueue为目标的监听器端点:

@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}
}

具体查看@EnableJms javadoc

如果想创建多个JmsListenerContainerFactory实例或覆盖默认实例,你可以使用Spring Boot提供的DefaultJmsListenerContainerFactoryConfigurer,通过它可以使用跟自动配置的实例相同配置来初始化一个DefaultJmsListenerContainerFactory

例如,以下使用一个特殊的MessageConverter创建另一个factory:

@Configuration
static class JmsConfiguration {

    @Bean
    public DefaultJmsListenerContainerFactory myFactory(
            DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory =
                new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, connectionFactory());
        factory.setMessageConverter(myMessageConverter());
        return factory;
    }

}

然后,你可以像下面那样在任何@JmsListener注解中使用:

@Component
public class MyBean {

    @JmsListener(destination = "someQueue", containerFactory="myFactory")
    public void processMessage(String content) {
        // ...
    }

}

32.2 AMQP

高级消息队列协议(AMQP)是一个用于消息中间件的,平台无关的,线路级(wire-level)协议。Spring AMQP项目使用Spring的核心概念开发基于AMQP的消息解决方案,Spring Boot为通过RabbitMQ使用AMQP提供了一些便利,包括spring-boot-starter-amqp‘Starter’。

32.2.1 RabbitMQ支持

RabbitMQ是一个基于AMQP协议,轻量级的,可靠的,可扩展的和可移植的消息代理,Spring就使用它进行消息传递。RabbitMQ配置被外部属性spring.rabbitmq.*控制,例如,在application.properties中声明以下片段:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret

更多选项参考RabbitProperties

32.1.2 Artemis支持

Apache Artemis成立于2015年,那时HornetQ刚捐给Apache基金会,确保别使用了过期的HornetQ支持。 不要尝试同时使用Artemis和HornetQ。

如果发现classpath下存在Artemis依赖,Spring Boot将自动配置一个ConnectionFactory。如果需要broker,Spring Boot将启动内嵌的broker,并对其自动配置(除非模式mode属性被显式设置)。支持的modes包括:embedded(明确需要内嵌broker,如果classpath下不存在则出错),native(使用netty传输协议连接broker)。当配置native模式,Spring Boot将配置一个连接broker的ConnectionFactory,该broker使用默认的设置运行在本地机器。 使用spring-boot-starter-artemis 'Starter',则连接已存在的Artemis实例及Spring设施集成JMS所需依赖都会提供,添加org.apache.activemq:artemis-jms-server依赖,你可以使用内嵌模式。

Artemis配置控制在外部配置属性spring.artemis.*中,例如,在application.properties声明以下片段:

spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret

当使用内嵌模式时,你可以选择是否启用持久化,及目的地列表。这些可以通过逗号分割的列表来指定,也可以分别定义org.apache.activemq.artemis.jms.server.config.JMSQueueConfigurationorg.apache.activemq.artemis.jms.server.config.TopicConfiguration类型的bean来进一步配置队列和topic,具体支持选项可参考ArtemisProperties

32.1.3 HornetQ支持

HornetQ在1.4版本已过期,可以考虑迁移到artemis

如果在classpath下发现HornetQ,Spring Boot会自动配置ConnectionFactory。如果需要代理,将会开启一个内嵌的,已经自动配置好的代理(除非显式设置mode属性)。支持的modes有:embedded(显式声明使用内嵌的代理,如果该代理在classpath下不可用将出错),native(使用netty传输协议连接代理)。当后者被配置,Spring Boot配置一个连接到代理的ConnectionFactory,该代理运行在使用默认配置的本地机器上。

:如果使用spring-boot-starter-hornetq,连接到一个已存在的HornetQ实例所需的依赖都会被提供,同时还有用于集成JMS的Spring基础设施。将org.hornetq:hornetq-jms-server添加到应用中,你就可以使用embedded模式。

HornetQ配置被spring.hornetq.*中的外部配置属性所控制,例如,在application.properties声明以下片段:

spring.hornetq.mode=native
spring.hornetq.host=192.168.1.210
spring.hornetq.port=9876

当内嵌代理时,你可以选择是否启用持久化,并且列表中的目标都应该是可用的。这些可以通过一个以逗号分割的列表来指定一些默认的配置项,或定义org.hornetq.jms.server.config.JMSQueueConfigurationorg.hornetq.jms.server.config.TopicConfiguration类型的bean(s)来配置更高级的队列和主题,具体参考HornetQProperties

没有涉及JNDI查找,目标是通过名字解析的,名字即可以使用HornetQ配置中的name属性,也可以是配置中提供的names。

32.1.4 使用JNDI ConnectionFactory

如果你的App运行在应用服务器中,Spring Boot将尝试使用JNDI定位一个JMS ConnectionFactory,默认会检查java:/JmsXAjava:/ XAConnectionFactory两个地址。如果需要指定替换位置,可以使用spring.jms.jndi-name属性:

spring.jms.jndi-name=java:/MyConnectionFactory

32.1.5 发送消息

Spring的JmsTemplate会被自动配置,你可以将它直接注入到自己的beans中:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JmsTemplate jmsTemplate;
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
// ...
}

你可以使用相同方式注入JmsMessagingTemplate。如果定义了DestinationResolverMessageConverter beans,它们将自动关联到自动配置的JmsTemplate

32.1.6 接收消息

当JMS基础设施能够使用时,任何bean都能够被@JmsListener注解,以创建一个监听者端点。如果没有定义JmsListenerContainerFactory,将自动配置一个默认的。如果定义DestinationResolverMessageConverter beans,它们将自动关联该默认factory。

默认factory是事务性的,如果运行的设施出现JtaTransactionManager,它默认将关联到监听器容器。如果没有,sessionTransacted标记将启用。在后一场景中,你可以通过在监听器方法上添加@Transactional,以本地数据存储事务处理接收的消息,这可以确保接收的消息在本地事务完成后只确认一次。

下面的组件创建了一个以someQueue为目标的监听器端点:

@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}
}

具体查看@EnableJms javadoc

如果想创建多个JmsListenerContainerFactory实例或覆盖默认实例,你可以使用Spring Boot提供的DefaultJmsListenerContainerFactoryConfigurer,通过它可以使用跟自动配置的实例相同配置来初始化一个DefaultJmsListenerContainerFactory

例如,以下使用一个特殊的MessageConverter创建另一个factory:

@Configuration
static class JmsConfiguration {

    @Bean
    public DefaultJmsListenerContainerFactory myFactory(
            DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory =
                new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, connectionFactory());
        factory.setMessageConverter(myMessageConverter());
        return factory;
    }

}

然后,你可以像下面那样在任何@JmsListener注解中使用:

@Component
public class MyBean {

    @JmsListener(destination = "someQueue", containerFactory="myFactory")
    public void processMessage(String content) {
        // ...
    }

}

32.2 AMQP

高级消息队列协议(AMQP)是一个用于消息中间件的,平台无关的,线路级(wire-level)协议。Spring AMQP项目使用Spring的核心概念开发基于AMQP的消息解决方案,Spring Boot为通过RabbitMQ使用AMQP提供了一些便利,包括spring-boot-starter-amqp‘Starter’。

32.2.1 RabbitMQ支持

RabbitMQ是一个基于AMQP协议,轻量级的,可靠的,可扩展的和可移植的消息代理,Spring就使用它进行消息传递。RabbitMQ配置被外部属性spring.rabbitmq.*控制,例如,在application.properties中声明以下片段:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret

更多选项参考RabbitProperties

32.2.2 发送消息

Spring的AmqpTemplateAmqpAdmin会被自动配置,你可以将它们直接注入beans中:

import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyBean {

    private final AmqpAdmin amqpAdmin;
    private final AmqpTemplate amqpTemplate;

    @Autowired
    public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate amqpTemplate) {
        this.amqpAdmin = amqpAdmin;
        this.amqpTemplate = amqpTemplate;
    }

    // ...

}

可以使用相似方式注入RabbitMessagingTemplate,如果定义MessageConverter bean,它将自动关联到自动配置的AmqpTemplate

如果需要的话,所有定义为bean的org.springframework.amqp.core.Queue将自动在RabbitMQ实例中声明相应的队列。你可以启用AmqpTemplate的重试选项,例如代理连接丢失时,重试默认不启用。

32.2.3 接收消息

当Rabbit设施出现时,所有bean都可以注解@RabbitListener来创建一个监听器端点。如果没有定义RabbitListenerContainerFactory,Spring Boot将自动配置一个默认的。如果定义MessageConverter beans,它将自动关联到默认的factory。

下面的组件创建一个someQueue队列上的监听器端点:

@Component
public class MyBean {

    @RabbitListener(queues = "someQueue")
    public void processMessage(String content) {
        // ...
    }

}

具体参考@EnableRabbit

如果需要创建多个RabbitListenerContainerFactory实例,或想覆盖默认实例,你可以使用Spring Boot提供的SimpleRabbitListenerContainerFactoryConfigurer,通过它可以使用跟自动配置实例相同的配置初始化SimpleRabbitListenerContainerFactory

例如,下面使用一个特殊的MessageConverter创建了另一个factory:

@Configuration
static class RabbitConfiguration {

    @Bean
    public SimpleRabbitListenerContainerFactory myFactory(
            SimpleRabbitListenerContainerFactoryConfigurer configurer) {
        SimpleRabbitListenerContainerFactory factory =
                new SimpleRabbitListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        factory.setMessageConverter(myMessageConverter());
        return factory;
    }

}

然后,你可以像下面那样在所有@RabbitListener注解方法中使用:

@Component
public class MyBean {

    @RabbitListener(queues = "someQueue", containerFactory="myFactory")
    public void processMessage(String content) {
        // ...
    }

}

你可以启动重试处理那些监听器抛出异常的情况,当重试次数达到限制时,该消息将被拒绝,要不被丢弃,要不路由到一个dead-letter交换器,如果broker这样配置的话,默认禁用重试。

重要 如果没启用重试,且监听器抛出异常,则Rabbit会不定期进行重试。你可以采用两种方式修改该行为:设置defaultRequeueRejected属性为false,这样就不会重试;或抛出一个AmqpRejectAndDontRequeueException异常表示该消息应该被拒绝,这是开启重试,且达到最大重试次数时使用的策略。